/** \file
* POSIX-specific implementation of the XML file source class.
* This file is part of Chorus, available at
* http://code.google.com/p/chorus-twitter/ . This file and all associated files
* and derivative works are bound by the terms of the LGPL 3.0 license,
* available at http://www.gnu.org/licenses/lgpl-3.0-standalone.html .
* \par Subversion URL:
* \$URL: http://chorus-twitter.googlecode.com/svn/branches/cpp/src/xml/posix/XmlFileSource.cpp $
* \version \$Rev: 153 $
* \date    \$Date: 2010-04-06 07:43:42 +0000 (Tue, 06 Apr 2010) $
*/

#define NEEDS_POSIX
#include "config.h"

#include <fcntl.h>
#include <unistd.h>

#ifdef __unix__
#	include <asm/ioctls.h>
#	include <stropts.h>
#endif

#ifdef __APPLE__
#	include <sys/ioctl.h>
#endif

#include "system/DebugConsole.hpp"
#include "xml/XmlFileSource.hpp"

using namespace std;

XmlFileSource::XmlFileSource(XmlTree *treeInit, const char *pathInit) :
	XmlSource(treeInit, localizePath(pathInit))
{
}

XmlFileSource::~XmlFileSource()
{
}

std::string XmlFileSource::localizePath(const char *pathInit)
{
	string syspath = "/home/greg/.chorus/";
	syspath += pathInit;
	return syspath;
}

bool XmlFileSource::perform()
{
	const int fd = open(path.c_str(), O_RDONLY|O_NONBLOCK);
	if (fd == -1)
	{
		PDEBUG_C_ERRNO("open failed");
		return false;
	}

	bool success = false;

	timeval timeout;
	timeout.tv_sec = 10;
	timeout.tv_usec = 0;

	char *buffer = 0;

	for (;;)
	{
		fd_set rdset;
		FD_ZERO(&rdset);
		FD_SET(fd, &rdset);
		fd_set erset = rdset;

		const int nsel = select(fd+1, &rdset, 0, &erset, &timeout);
		if (nsel < 1)
		{
			PDEBUG_C_ERRNO("select failed");
			goto fail; // Failure or timeout
		}
		if (FD_ISSET(fd, &erset))
		{
			PDEBUG("error set from select");
			goto fail;
		}
		if (FD_ISSET(fd, &rdset))
		{
			int len;
			if (ioctl(fd, FIONREAD, &len) == -1)
			{
				PDEBUG_C_ERRNO("ioctl failed:");
				goto fail;
			}
			if (len < 1)
				break;	// EOF
			buffer = new char[len];
			if (!buffer)
			{
				PDEBUG("new failed");
				goto fail;
			}
			const int bytesread = read(fd, buffer, len);
			if (bytesread < 1)
			{
				PDEBUG_C_ERRNO("read failed");
				goto fail;
			}
			if (!writeData(buffer, bytesread))
				goto fail;
			delete [] buffer;
			buffer = 0;
		}
	}

	success = true;
	fail:
	if (buffer)
		delete [] buffer;
	if (close(fd) == -1)
		return false;
	return success;
}
